package com.lt.integration.jpa.component;

import com.lt.integration.jpa.component.common.Direction;
import com.lt.integration.jpa.component.hibernate.Updater;
import com.lt.integration.jpa.page.Pagination;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.metamodel.Attribute;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;


/**
 * 基础查询Service抽象实现
 * @author xiaobin
 *
 * @param <T>
 * @param <QO>
 */
@Transactional
public class BaseServiceImpl<T extends BaseModel, QO extends BaseQO> implements BaseService<T, QO> {

	/**
	 * 自动注入dao 泛型式依赖注入
	 */
	@Autowired
	protected BaseDao<T, QO> dao;

	/**
	 * 默认id
	 */
	private static final String DEFAULT_ID = "id";

	/**
	 * 根据ID获取实体
	 *
	 * @param id 查询的id
	 * @return 实体
	 */
	@Override
	@Transactional(readOnly=true)
	public T get(Long id) {
		return dao.findById(id).orElseGet(() -> null);
	}

	/**
	 * @param id 查询的id
	 * @return 实体
	 */
	@Override
	@Transactional(readOnly=true)
	public Optional<T> getById(Long id) {
		return dao.findById(id);
	}

	/**
	 * 查询唯一对象
	 *
	 * @param qo 查询对象
	 * @return 查询实体
	 */
	@Override
	@Transactional(readOnly=true)
	public T queryUnique(QO qo) {
		return dao.queryUnique(qo);
	}

	/**
	 * 查询唯一对象 可查询关联对象
	 *
	 * @param qo 查询对象
	 * @return 查询实体
	 */
	@Override
	@Transactional(readOnly=true)
	public T fetchUnique(QO qo) {
		return dao.fetchUnique(qo);
	}

	/**
	 * 查询所有记录
	 *
	 * @return 返回所有记录
	 */
	@Override
	@Transactional(readOnly=true)
	public List<T> queryAll() {
		return dao.findAll();
	}

	/**
	 * 查询所有记录 id desc排序
	 * @return 返回所有记录
	 */
	@Override
	public List<T> queryAllOrderByIdDesc() {
		Sort sort = Sort.by(Sort.Direction.DESC, DEFAULT_ID);
		return dao.findAll(sort);
	}

	/**
	 * 查询对象列表
	 *
	 * @param qo 查询对象
	 * @return 查询实体列表
	 */
	@Override
	@Transactional(readOnly=true)
	public List<T> queryList(QO qo) {
		return dao.queryList(qo);
	}

	/**
	 * 查询实体列表
	 *
	 * @param qo      查询对象
	 * @param maxSize 最大获取数量
	 * @return 查询实体列表
	 */
	@Override
	@Transactional(readOnly=true)
	public List<T> queryList(QO qo, Integer maxSize) {
		return dao.queryList(qo, maxSize);
	}

	/**
	 * 查询实体列表
	 *
	 * @param qo      查询对象
	 * @param offset  偏移量
	 * @param maxSize 最大获取数量
	 * @return 列表
	 */
	@Override
	@Transactional(readOnly=true)
	public List<T> queryList(QO qo, Integer offset, Integer maxSize) {
		return dao.queryList(qo, offset, maxSize);
	}

	/**
	 * 查询数量
	 *
	 * @param qo 查询对象
	 * @return 查询数量
	 */
	@Override
	@Transactional(readOnly=true)
	public Long queryCount(QO qo) {
		return dao.count(qo);
	}

	/**
	 * 查询数量
	 *
	 * @param qo 查询对象
	 * @return 查询数量
	 */
	public Long count(QO qo) {
		return dao.count(qo);
	}

	/**
	 * 分页查询对象
	 *
	 * @param qo 查询对象
	 * @return 查询实体分页列表
	 */
	@Override
	@Transactional(readOnly=true)
	public Pagination<T> queryPagination(QO qo) {
		return dao.queryPagination(qo);
	}

	/**
	 * 分页查询对象
	 *
	 * @param pagination
	 * @return 查询实体分页列表
	 */
	@Override
	@Transactional(readOnly=true)
	public Pagination<T> queryPagination(Pagination<T> pagination) {
		return dao.queryPagination(pagination);
	}

	/**
	 * 根据id的升序或者降序排序
	 *
	 * @param id 大于或小于此id的数据
	 * @param qo 每页的数量 默认为10
	 * @return 查询实体分页列表
	 */
	@Override
	@Transactional(readOnly=true)
	public Pagination<T> queryPagination(Long id, QO qo) {
		return dao.queryPagination(id, qo);
	}

	/**
	 * 根据id的升序或者降序排序
	 *
	 * @param id        大于或小于此id的数据
	 * @param qo
	 * @param direction 排序 升序或者降序 默认为 {@link Direction#ASC}
	 * @return 查询实体分页列表
	 */
	@Override
	@Transactional(readOnly=true)
	public Pagination<T> queryPagination(Long id, QO qo, Direction direction) {
		return dao.queryPagination(id, qo, direction);
	}

	/**
	 * 通过updater更新 可以通过updater指定需要更新的字段
	 *
	 * @param updater
	 * @return 更新的记录数
	 */
	@Override
	public int update(Updater updater) {
		return dao.update(updater);
	}

	/**
	 * @param id        更新的记录的id
	 * @param attribute 更新的字段
	 * @param value     更新的记录的值
	 * @return 更新的记录数
	 */
	@Override
	public int update(Long id, Attribute<?, ?> attribute, Object value) {
		return dao.update(id, attribute, value);
	}

	/**
	 * @param id     更新的记录的id
	 * @param params 更新的字段和值
	 * @return 更新的记录数
	 */
	@Override
	public int update(Long id, Map<Attribute<?, ?>, Object> params) {
		return dao.update(id, params);
	}

	/**
	 * 保存
	 *
	 * @param entity 更新实体
	 * @return
	 */
	@Override
	public T update(T entity) {
		return dao.update(entity);
	}

	/**
	 * 保存
	 *
	 * @param entity 保存实体
	 * @return
	 */
	@Override
	public T save(T entity) {
		return dao.save(entity);
	}

	/**
	 * 直接保存
	 *
	 * @param entity 保存实体
	 * @return
	 */
	@Override
	public T persist(T entity) {
		return dao.persist(entity);
	}

	/**
	 * 批量保存实体
	 *
	 * @param entities 保存的实体
	 */
	@Override
	public void saveArray(T... entities) {
		List<T> list = new ArrayList<>();
		for (T t : entities) {
			list.add(t);
		}
		dao.batchSave(list);
	}

	/**
	 * 批量保存实体
	 *
	 * @param entities 保存的实体
	 */
	@Override
	public void saveList(List<T> entities) {
		dao.batchSave(entities);
	}

	/**
	 * Flushes all pending changes to the database.
	 */
	@Override
	public void flush() {
		dao.flush();
	}

	/**
	 * Saves an entity and flushes changes instantly.
	 *
	 * @param entity
	 * @return the saved entity
	 */
	@Override
	public T saveAndFlush(T entity) {
		return dao.saveAndFlush(entity);
	}

	/**
	 * 批量更新实体
	 *
	 * @param entities 更新的实体
	 */
	@Override
	public void updateArray(T... entities) {
		List<T> list = new ArrayList<>();
		for (T t : entities) {
			list.add(t);
		}
		dao.batchUpdate(list);
	}

	/**
	 * 批量更新实体
	 *
	 * @param entities 更新的实体
	 */
	@Override
	public void updateList(List<T> entities) {
		dao.batchUpdate(entities);
	}

	/**
	 * 批量删除
	 *
	 * @param entities 要删除的实体
	 */
	@Override
	public void batchDelete(List<T> entities) {
		dao.batchDelete(entities);
	}

	/**
	 * 根据ID删除实体（物理删除）
	 *
	 * @param id 实体主键
	 */
	@Override
	public void deleteById(Long id) {
		dao.deleteById(id);
	}

	/**
	 * 根据ID数组批量删除实体
	 *
	 * @param ids 实体主键
	 */
	@Override
	public void deleteByIds(Long... ids) {
		for (Long id : ids) {
			dao.deleteById(id);
		}
	}
}
